class EstatisticasNfeController < ApplicationController

#CREATE INDEX idx_logs_operacao
#  ON logs
#  USING btree
#  (operacao, ano, mes, dia, hora);
#
#CREATE INDEX idx_logs_timestamp
#  ON logs
#  USING btree
#  ("timestamp");
#

  SERVIDOR_1 = 1
  SERVIDOR_2 = 2
  ARQUIVO_SERVIDOR_1 = "d:/xxx.log"
  ARQUIVO_SERVIDOR_2 = "d:/app_42.log"

  OPERACOES = ['NfeRecepcao.nfeRecepcaoLote',
               'NfeRetRecepcao.nfeRetRecepcao',
               'NfeStatusServico.nfeStatusServicoNF',
               'NfeConsulta.nfeConsultaNF',
               'CadConsultaCadastro.consultaCadastro',
               'NfeInutilizacao.nfeInutilizacaoNF',
               'NfeCancelamento.nfeCancelamentoNF',

               'NotaFiscalManager.findByChaveAcesso',
               'NotaFiscalManager.autorizar',
               'NotaFiscalManager.cancelar',
               'NotaFiscalManager.findByAnoCnpjModeloSerieNumero',
               'NotaFiscalManager.existeNotaByAnoCnpjModeloSerieNumeroIniFim',
               'LoteManager.incorporar',
               'LoteManager.atualizar',
               'LoteManager.findByNumeroRecibo',
               'ContribuinteManager.findByNumeroIE',
               'ContribuinteManager.findByNumeroCNPJ',
               'TeddistManager.enviarNota',
               'TeddistManager.enviarCancelamento',
               'TeddistManager.enviarInutilizacao',
               'TeddistManager.findByNumeroProtocolo',
               'InutilizacaoManager.inutilizar',
               'InutilizacaoManager.isFaixaInutilizacaoValida',
               'InutilizacaoManager.findByAnoCnpjModeloSerieNumero',
               'LogManager.gravarLog',

               'A', 'B', 'C', 'D', 'E', 'F',
               'G02', 'G03', 'G03a', 'G03b', 'G04', 'G05', 'G05a', 'G05b', 'G06',
               'G06a', 'G06b', 'G06c', 'G06d', 'G07', 'G08', 'G08a', 'G09', 'G10',
               'G10a', 'G10b', 'G11', 'G11a', 'G12', 'G13', 'G13a', 'G14', 'G15',
               'G16', 'G17', 'G18', 'G19', 'G20', 'G21', 'G22', 'G23', 'G24', 'G25',
               'G25a', 'G25b', 'G25c', 'G25d', 'G25e', 'G25f', 'G26', 'G29', 'G30',
               'H02', 'H03', 'H04', 'H05', 'H06', 'H07', 'H08', 'H10', 'H11', 'H13',
               'I02', 'I03', 'I04', 'I05', 'I06', 'I07', 'I08', 'J02', 'J03', 'J04',
               'K02', 'L01', 'L02', 'L03', 'L04', 'L05', 'L06', 'L07', 'M02', 'M03',
               'M04', 'M05', 'TIPO_AMB' ]

  NOMES_OPERACOES = { 0   => 'WS Recepção de Lotes',
                      1   => 'WS Retorno da Recepção',
                      2   => 'WS Status do Serviço',
                      3   => 'WS Consulta NF-e',
                      4   => 'WS Consulta Cadastro',
                      5   => 'WS Inutilização de NF-e',
                      6   => 'WS Cancelamento de NF-e',
                      7   => 'NfeConsultaNFe.nfeConsultaNFeLog',
                      8   => 'OP Buscar Nota pela Chave de Acesso',
                      9   => 'OP Autorizar NF-e',
                      10  => 'OP Cancelar NF-e',
                      11  => 'OP Buscar Nota por Ano Cnpj Modelo Serie Numero',
                      12  => 'OP Buscar Nota por Ano Cnpj Modelo Serie Numero Ini Fim',
                      13  => 'OP Incorporar Lote',
                      14  => 'OP Atualizar Lote',
                      15  => 'OP Buscar Lote por Numero do Recibo',
                      16  => 'OP Buscar Contribuinte por Numero IE',
                      17  => 'OP Buscar Contribuinte por Numero CNPJ',
                      18  => 'OP Enviar Nota TEDDIST',
                      19  => 'OP Enviar Cancelamento TEDDIST',
                      20  => 'OP Enviar Inutilizacao TEDDIST',
                      21  => 'OP Buscar TedDist pro Numero do Protocolo',
                      22  => 'OP Inutilizar NF-e',
                      23  => 'OP Validar Faixa de Inutilizacao',
                      24  => 'OP Buscar Inutilizacao por Ano Cnpj Modelo Serie Numero',
                      25  => 'OP Gravar Log Servico',
                      26  => 'RN ' + OPERACOES[25],
                      27  => 'RN ' + OPERACOES[26],
                      28  => 'RN ' + OPERACOES[27],
                      29  => 'RN ' + OPERACOES[28],
                      30  => 'RN ' + OPERACOES[29],
                      31  => 'RN ' + OPERACOES[30],
                      32  => 'RN ' + OPERACOES[31],
                      33  => 'RN ' + OPERACOES[32],
                      34  => 'RN ' + OPERACOES[33],
                      35  => 'RN ' + OPERACOES[34],
                      36  => 'RN ' + OPERACOES[35],
                      37  => 'RN ' + OPERACOES[36],
                      38  => 'RN ' + OPERACOES[37],
                      39  => 'RN ' + OPERACOES[38],
                      40  => 'RN ' + OPERACOES[39],
                      41  => 'RN ' + OPERACOES[40],
                      42  => 'RN ' + OPERACOES[41],
                      43  => 'RN ' + OPERACOES[42],
                      44  => 'RN ' + OPERACOES[43],
                      45  => 'RN ' + OPERACOES[44],
                      46  => 'RN ' + OPERACOES[45],
                      47  => 'RN ' + OPERACOES[46],
                      48  => 'RN ' + OPERACOES[47],
                      49  => 'RN ' + OPERACOES[48],
                      50  => 'RN ' + OPERACOES[49],
                      51  => 'RN ' + OPERACOES[50],
                      52  => 'RN ' + OPERACOES[51],
                      53  => 'RN ' + OPERACOES[52],
                      54  => 'RN ' + OPERACOES[53],
                      55  => 'RN ' + OPERACOES[54],
                      56  => 'RN ' + OPERACOES[55],
                      57  => 'RN ' + OPERACOES[56],
                      58  => 'RN ' + OPERACOES[57],
                      59  => 'RN ' + OPERACOES[58],
                      60  => 'RN ' + OPERACOES[59],
                      61  => 'RN ' + OPERACOES[60],
                      62  => 'RN ' + OPERACOES[61],
                      63  => 'RN ' + OPERACOES[62],
                      64  => 'RN ' + OPERACOES[63],
                      65  => 'RN ' + OPERACOES[64],
                      66  => 'RN ' + OPERACOES[65],
                      67  => 'RN ' + OPERACOES[66],
                      68  => 'RN ' + OPERACOES[67],
                      69  => 'RN ' + OPERACOES[68],
                      70  => 'RN ' + OPERACOES[69],
                      71  => 'RN ' + OPERACOES[70],
                      72  => 'RN ' + OPERACOES[71],
                      73  => 'RN ' + OPERACOES[72],
                      74  => 'RN ' + OPERACOES[73],
                      75  => 'RN ' + OPERACOES[74],
                      76  => 'RN ' + OPERACOES[75],
                      77  => 'RN ' + OPERACOES[76],
                      78  => 'RN ' + OPERACOES[77],
                      79  => 'RN ' + OPERACOES[78],
                      80  => 'RN ' + OPERACOES[79],
                      81  => 'RN ' + OPERACOES[80],
                      82  => 'RN ' + OPERACOES[81],
                      83  => 'RN ' + OPERACOES[82],
                      84  => 'RN ' + OPERACOES[83],
                      85  => 'RN ' + OPERACOES[84],
                      86  => 'RN ' + OPERACOES[85],
                      87  => 'RN ' + OPERACOES[86],
                      88  => 'RN ' + OPERACOES[87],
                      89  => 'RN ' + OPERACOES[88],
                      90  => 'RN ' + OPERACOES[89],
                      91  => 'RN ' + OPERACOES[90],
                      92  => 'RN ' + OPERACOES[91],
                      93  => 'RN ' + OPERACOES[92],
                      94  => 'RN ' + OPERACOES[93],
                      95  => 'RN ' + OPERACOES[94],
                      96  => 'RN ' + OPERACOES[95],
                      97  => 'RN ' + OPERACOES[96],
                      98  => 'RN ' + OPERACOES[97],
                      99  => 'RN ' + OPERACOES[98],
                      100 => 'RN ' + OPERACOES[99],
                      101 => 'RN ' + OPERACOES[100],
                      102 => 'RN ' + OPERACOES[101],
                      103 => 'RN ' + OPERACOES[102],
                      104 => 'RN ' + OPERACOES[103],
                      105 => 'RN ' + OPERACOES[104],
                      106 => 'RN ' + OPERACOES[105],
                      107 => 'RN ' + OPERACOES[106],
                      108 => 'RN ' + OPERACOES[107],
                      109 => 'RN ' + OPERACOES[108],
                      110 => 'RN ' + OPERACOES[109] }

  def atualizar
#    carga_incremental(ARQUIVO_SERVIDOR_1, SERVIDOR_1)
#    carga_incremental(ARQUIVO_SERVIDOR_2, SERVIDOR_2)
  end

  def carregar
#    carga_total(ARQUIVO_SERVIDOR_1, SERVIDOR_1)
    carga_total(ARQUIVO_SERVIDOR_2, SERVIDOR_2)
  end

  def carga_incremental(arquivo, servidor)
    arquivo_log = File.open(arquivo, "r")

    ultimo_timestamp = Log.scoped_by_servidor(servidor).maximum('timestamp')
    ultimo_log = Log.scoped_by_servidor(servidor).find_by_timestamp(ultimo_timestamp, :limit => 1)
    ultima_operacao = ultimo_log.operacao

    arquivo_log.detect { |obj|  obj =~ /^#{ultimo_timestamp}\s\d{13}\s#{ultima_operacao}/}
 
    while linha = arquivo_log.gets do
      linha = linha.split
      salvar_log(linha, servidor)
    end
  end

  def carga_total(arquivo, servidor)
    arquivo_log = File.open(arquivo, "r")

    arquivo_log.each do |linha|
      linha = linha.split
      salvar_log(linha, servidor)
    end

  end

  def salvar_log(linha, servidor)
    log = Log.new

    log.servidor = servidor
    log.timestamp = linha[0].to_i
    log.duracao = (linha[1].to_i - linha[0].to_i)
    log.operacao = linha[2]

    # Nem todas as linhas possuem o CNPJ
    log.cnpj = linha[3] if linha[3]

    milis = Time.at(linha[0].to_i / 1000)
    log.ano = milis.strftime('%Y').to_i
    log.mes = milis.strftime('%m').to_i
    log.dia = milis.strftime('%d').to_i
    log.hora = milis.strftime('%H').to_i
    log.minuto = milis.strftime('%M').to_i
    log.segundo = milis.strftime('%S').to_i

    log.save
  end

  def index
    # As dimensões do grafico são uma aproximação da razão aurea

    tamanho_horizontal = 600
    tamanho_vertical   = 371

    #Gera um array com as opções e indices para ser usado como parametro do metodo
    #options_for_select do helper que gera o combo de operacoes
    @opcoes_combo_operacao = NOMES_OPERACOES.select {|k,v| true}
    @opcoes_combo_operacao.collect! { |x| [x[1],x[0]] }
    @opcoes_combo_operacao.sort! { |x,y| x[1] <=> y[1] }
    
    @tempo_resposta_instantaneo = ""
    @quantitativo_instantaneo = ""
    
    @tempo_resposta_horario = ""
    @quantitativo_horario = ""

    @tempo_resposta_diario = ""
    @quantitativo_diario = ""

    @tempo_resposta_mensal = ""
    @quantitativo_mensal = ""

    @tempo_resposta_anual = ""
    @quantitativo_anual = ""

    @operacao = params[:operacao] || '0'

    case params[:grafico]
    when 'diario':

      filtro = params[:filtro_diario] || {}
      @ano = filtro['ano_mes(1i)'] ? filtro['ano_mes(1i)'] : Time.now.strftime('%Y')

      filtro['ano_mes(2i)'] ||= Time.now.strftime('%m')
      @mes = filtro['ano_mes(2i)'].rjust(2,"0")

      @tempo_resposta_diario = open_flash_chart_object(tamanho_horizontal,tamanho_vertical,"/estatisticas_nfe/grafico_diario_tempo_resposta?ano=#{@ano}&mes=#{@mes}&operacao=#{@operacao}")
      @quantitativo_diario = open_flash_chart_object(tamanho_horizontal,tamanho_vertical,"/estatisticas_nfe/grafico_diario_quantitativo?ano=#{@ano}&mes=#{@mes}&operacao=#{@operacao}")

    when 'mensal':

      filtro = params[:filtro_mensal] || {}
      @ano = filtro['ano_mes(1i)'] ? filtro['ano_mes(1i)'] : Time.now.strftime('%Y')

      @tempo_resposta_mensal = open_flash_chart_object(tamanho_horizontal,tamanho_vertical,"/estatisticas_nfe/grafico_mensal_tempo_resposta?ano=#{@ano}&operacao=#{@operacao}")
      @quantitativo_mensal = open_flash_chart_object(tamanho_horizontal,tamanho_vertical,"/estatisticas_nfe/grafico_mensal_quantitativo?ano=#{@ano}&operacao=#{@operacao}")

    when 'anual':

      @tempo_resposta_anual = open_flash_chart_object(tamanho_horizontal,tamanho_vertical,"/estatisticas_nfe/grafico_anual_tempo_resposta?operacao=#{@operacao}")
      @quantitativo_anual = open_flash_chart_object(tamanho_horizontal,tamanho_vertical,"/estatisticas_nfe/grafico_anual_quantitativo?operacao=#{@operacao}")

    else  # default => horário ou instantâneo

      filtro = params[:filtro_horario] || {}

      @ano = filtro['ano_mes(1i)'] ? filtro['ano_mes(1i)'] : Time.now.strftime('%Y')
      @mes = filtro['ano_mes(2i)'] ? filtro['ano_mes(2i)'].rjust(2,"0") : Time.now.strftime('%m')
      @dia = filtro['ano_mes(3i)'] ? filtro['ano_mes(3i)'].rjust(2,"0") : Time.now.strftime('%d')

      @tempo_resposta_horario = open_flash_chart_object(tamanho_horizontal,tamanho_vertical,"/estatisticas_nfe/grafico_horario_tempo_resposta?ano=#{@ano}&mes=#{@mes}&dia=#{@dia}&operacao=#{@operacao}", true, "/", "open-flash-chart-bar-clicking.swf")
      @quantitativo_horario = open_flash_chart_object(tamanho_horizontal,tamanho_vertical,"/estatisticas_nfe/grafico_horario_quantitativo?ano=#{@ano}&mes=#{@mes}&dia=#{@dia}&operacao=#{@operacao}", true, "/", "open-flash-chart-bar-clicking.swf")

#      @tempo_resposta_instantaneo_recepcao = open_flash_chart_object(tamanho_horizontal,tamanho_vertical,"/estatisticas_nfe/grafico_instantaneo_tempo_resposta_recepcao_lote")
#      @quantitativo_instantaneo_recepcao = open_flash_chart_object(tamanho_horizontal,tamanho_vertical,"/estatisticas_nfe/grafico_instantaneo_quantitativo_recepcao_lote")

    end
  end

  def configurar_grafico(dados=[], titulo='Título do Gráfico', texto_x='Legenda X', quantitativo=false, drilldown=false )

    max = 0
    min = 0
    valores = []
    datas = []

    dados.each do |log|
      txt_x = log[0]
      datas << XAxisLabel.new(txt_x, '#000000', 11, '90')
      dado = quantitativo ? log[1] : (log[1].to_f / 1000.0).round(2)
      bv = BarValue.new(dado)
#      bv.on_click = "window.location='/estatisticas_nfe/listar?ano=#{@ano}&mes=#{@mes}&dia=#{@dia}&hora=#{txt_x}'" if drilldown
      bv.on_click = "relatorio(#{txt_x})" if drilldown
      valores << bv
      max = dado if dado > max
      min = dado if dado < min
    end

    title = Title.new(titulo) 
    title.set_style('{font: "Lucida Grande"; font-size: 16px; color: #005000}')

    serie = BarGlass.new
    serie.colour = '008000' #'#5E4725'

    serie.values = valores
    serie.text = quantitativo ? 'Quantidade de Acessos' : 'Média dos Tempos de Resposta'
    serie.font_size = 12

    x_labels = XAxisLabels.new
    x_labels.labels = datas

    x = XAxis.new
    x.set_labels(x_labels)

    x_legend = XLegend.new(texto_x)
    x_legend.set_style('{font: "Lucida Grande"; font-size: 16px; color: #005000}')

    texto_y = quantitativo ? 'Acessos' : 'Tempo em segundos'
    y_legend = YLegend.new(texto_y)
    y_legend.set_style('{font: "Lucida Grande"; font-size: 16px; color: #005000}')

    y = YAxis.new
    y.set_range(min, quantitativo ? (max + 1) : max, quantitativo ? (max + 1) / 10 : ((max - min) / 10.0))

    chart = OpenFlashChart.new
    chart.set_title(title)
    chart.set_x_legend(x_legend)
    chart.set_y_legend(y_legend)
    chart.x_axis = x
    chart.y_axis = y
    chart.add_element(serie)
    
    chart.to_s

  end

  def listar
    @ano  = params[:ano]  ? params[:ano]  : Time.now.strftime('%Y')
    @mes  = params[:mes]  ? params[:mes].rjust(2, "0")  : Time.now.strftime('%m')
    @dia  = params[:dia]  ? params[:dia].rjust(2, "0")  : Time.now.strftime('%d')
    @hora = params[:hora] ? params[:hora].rjust(2, "0") : Time.now.strftime('%hh')
    @nome_operacao = NOMES_OPERACOES[OPERACOES[params[:operacao].to_i]]
    @operacao = OPERACOES[params[:operacao].to_i]

    @logs = Log.scoped_by_operacao_and_ano_and_mes_and_dia_and_hora(@operacao, @ano, @mes, @dia, @hora).all(:order => 'timestamp')
    
  end

  def grafico_horario_tempo_resposta

    @ano = params[:ano] ? params[:ano] : Time.now.strftime('%Y')
    @mes = params[:mes] ? params[:mes] : Time.now.strftime('%m')
    @dia = params[:dia] ? params[:dia] : Time.now.strftime('%d')
    @nome_operacao = NOMES_OPERACOES[params[:operacao].to_i]
    @operacao = OPERACOES[params[:operacao].to_i]

    logs = Log.scoped_by_operacao_and_ano_and_mes_and_dia(@operacao, @ano, @mes, @dia).average('duracao',:group => 'hora', :order => 'hora') if params[:operacao]

    titulo = "Tempo de Resposta Médio - #{@nome_operacao[0,20]} - Horário\nData: #{@dia}/#{@mes}/#{@ano}\n "
    texto_x = "Horário"

    grafico = configurar_grafico(logs, titulo, texto_x, false, true)

    render :text => grafico
  end
  
  def grafico_horario_quantitativo

    @ano = params[:ano] ? params[:ano] : Time.now.strftime('%Y')
    @mes = params[:mes] ? params[:mes] : Time.now.strftime('%m')
    @dia = params[:dia] ? params[:dia] : Time.now.strftime('%d')
    @nome_operacao = NOMES_OPERACOES[params[:operacao].to_i]
    @operacao = OPERACOES[params[:operacao].to_i]

    logs = Log.scoped_by_operacao_and_ano_and_mes_and_dia(@operacao, @ano, @mes, @dia).count('id',:group => 'hora', :order => 'hora')

    titulo = "Número de Acessos - #{@nome_operacao[0,20]} - Horário\nData: #{@dia}/#{@mes}/#{@ano}\n "
    texto_x = "Horário"

    grafico = configurar_grafico(logs, titulo, texto_x, true, true)

    render :text => grafico
  end

  def grafico_diario_tempo_resposta

    @ano = params[:ano] ? params[:ano] : Time.now.strftime('%Y')
    @mes = params[:mes] ? params[:mes] : Time.now.strftime('%m')
    @nome_operacao = NOMES_OPERACOES[params[:operacao].to_i]
    @operacao = OPERACOES[params[:operacao].to_i]

    logs = Log.scoped_by_operacao_and_ano_and_mes(@operacao, @ano, @mes).average('duracao',:group => 'dia', :order => 'dia')

    titulo = "Tempo de Resposta Médio - #{@nome_operacao[0,20]} - Diário\nAno: #{@ano} Mês: #{@mes}\n "
    texto_x = "Dias"

    grafico = configurar_grafico(logs, titulo, texto_x)

    render :text => grafico
  end

  def grafico_diario_quantitativo

    @ano = params[:ano] ? params[:ano] : Time.now.strftime('%Y')
    @mes = params[:mes] ? params[:mes] : Time.now.strftime('%m')
    @nome_operacao = NOMES_OPERACOES[params[:operacao].to_i]
    @operacao = OPERACOES[params[:operacao].to_i]

    logs = Log.scoped_by_operacao_and_ano_and_mes(@operacao, @ano, @mes).count('id',:group => 'dia', :order => 'dia')

    titulo = "Número de Acessos - #{@nome_operacao[0,20]} - Diário\nAno: #{@ano} Mês: #{@mes}\n "
    texto_x = "Dias"

    grafico = configurar_grafico(logs, titulo, texto_x, true)

    render :text => grafico
  end

  def grafico_mensal_tempo_resposta

    @ano = params[:ano] ? params[:ano] : Time.now.strftime('%Y')
    @nome_operacao = NOMES_OPERACOES[params[:operacao].to_i]
    @operacao = OPERACOES[params[:operacao].to_i]

    logs = Log.scoped_by_operacao_and_ano(@operacao, @ano).average('duracao',:group => 'mes', :order => 'mes')

    titulo = "Tempo de Resposta Médio - #{@nome_operacao[0,20]} - Mensal\nAno: #{@ano}\n "
    texto_x = "Meses"

    grafico = configurar_grafico(logs, titulo, texto_x)

    render :text => grafico
  end

  def grafico_mensal_quantitativo

    @ano = params[:ano] ? params[:ano] : Time.now.strftime('%Y')
    @nome_operacao = NOMES_OPERACOES[params[:operacao].to_i]
    @operacao = OPERACOES[params[:operacao].to_i]

    logs = Log.scoped_by_operacao_and_ano(@operacao, @ano).count('id',:group => 'mes', :order => 'mes')

    titulo = "Número de Acessos - #{@nome_operacao[0,20]} - Mensal\nAno: #{@ano}\n "
    texto_x = "Meses"

    grafico = configurar_grafico(logs, titulo, texto_x, true)

    render :text => grafico
  end

  def grafico_anual_tempo_resposta

    @nome_operacao = NOMES_OPERACOES[params[:operacao].to_i]
    @operacao = OPERACOES[params[:operacao].to_i]

    logs = Log.scoped_by_operacao(@operacao).average('duracao',:group => 'ano', :order => 'ano')

    titulo = "Tempo de Resposta Médio - #{@nome_operacao[0,20]} - Histórico Ano a Ano\n "
    texto_x = "Anos"

    grafico = configurar_grafico(logs, titulo, texto_x)

    render :text => grafico
  end

  def grafico_anual_quantitativo

    @nome_operacao = NOMES_OPERACOES[params[:operacao].to_i]
    @operacao = OPERACOES[params[:operacao].to_i]

    logs = Log.scoped_by_operacao(@operacao).count('id',:group => 'ano', :order => 'ano')

    titulo = "Número de Acessos - #{@nome_operacao[0,20]} - Histórico Ano a Ano\n "
    texto_x = "Anos"

    grafico = configurar_grafico(logs, titulo, texto_x, true)

    render :text => grafico
  end

  def summary(file)
    f = File.open(file, "r")
    linhas = f.readlines.map {|line| line.split}
    linhas.each { |line| line.delete_at(2) }

    max = 0.0
    min = 0.0
    sum = 0.0
    linhas.each do |linha|
      tempo_milis = (linha[1].to_i - linha[0].to_i) / 1000.0
      max = tempo_milis if tempo_milis > max
      min = tempo_milis if tempo_milis < min
      sum += tempo_milis
    end
    puts "Tamanho: #{linhas.size}"
    puts "Tempo maximo: #{max} \t Tempo minimo: #{min} \t Media geral: #{sum / linhas.size}"
  end

  def formata_hora(hora)
    (hora.to_i + 1).to_s.rjust(2,"0") + ":00"
  end

end
